---
title: Concepts - Tasks
description: Understand the Task asynchronous primitive used in the @embedpdf/engines library.
searchable: true
---

# Tasks

import { Callout } from '@/components/callout'

All asynchronous methods in `@embedpdf/engines` return a `Task` object. A `Task` is a powerful alternative to a standard JavaScript `Promise`, designed specifically for handling complex operations like PDF processing.

## Why Use a Task?

While a `Promise` is excellent for representing a future value, a `Task` provides more control and features:

1.  **Cancellation (Aborting)**: Long-running operations, like rendering a large page or searching an entire document, can be aborted. This is crucial for building responsive UIs.
2.  **Progress Reporting**: Tasks can emit progress updates, allowing you to show loading bars or completion percentages for operations like `searchAllPages` or `getAllAnnotations`.
3.  **Clearer State Management**: A task has a distinct `Aborted` state in addition to the standard `Pending`, `Resolved`, and `Rejected` states.

## Working with Tasks

A `Task` can be used in two primary ways: by converting it to a `Promise` or by using its native callback-based `wait` method.

### Converting to a Promise (`.toPromise()`)

The easiest way to integrate a `Task` into modern JavaScript is to convert it to a `Promise` using the `.toPromise()` method. This allows you to use the familiar `async/await` syntax.

```typescript
// Assuming 'engine' is an initialized engine instance
async function getPageCount(url) {
  try {
    const document = await engine.openDocumentUrl({ id: 'doc1', url }).toPromise();
    console.log('Document opened successfully!');
    return document.pageCount;
  } catch (error) {
    // Note: The promise will reject for both 'rejected' and 'aborted' tasks.
    // You can check the error type if you need to distinguish them.
    if (error.name === 'TaskAbortedError') {
      console.log('The document opening task was aborted.');
    } else {
      console.error('Failed to open document:', error);
    }
    return 0;
  }
}
````
<Callout>
**Note**: When a `Task` is aborted, its corresponding `Promise` will **reject** with a `TaskAbortedError`.
</Callout>
### Using Callbacks (`.wait()`)

For more fine-grained control, you can use the `.wait()` method, which accepts `onResolved` and `onRejected` callbacks. This is the traditional way to handle the task's completion.

The `onRejected` callback receives an error object that distinguishes between a rejection and an abortion.

```typescript
const openTask = engine.openDocumentUrl({ id: 'doc1', url });

openTask.wait(
  // onResolved
  (document) => {
    console.log(`Success! Document has ${document.pageCount} pages.`);
  },
  // onRejected
  (error) => {
    if (error.type === 'abort') {
      console.log('Task was aborted with reason:', error.reason);
    } else {
      console.error('Task was rejected with reason:', error.reason);
    }
  }
);
```

### Handling Progress (`.onProgress()`)

For long-running operations, you can listen for progress updates. The `searchAllPages` method, for example, emits the results for each page as it completes.

```typescript
const searchTask = engine.searchAllPages(document, 'embedpdf');

// Listen for progress updates
searchTask.onProgress((progress) => {
  console.log(`Found ${progress.results.length} results on page ${progress.page}`);
});

// Handle the final result
searchTask.wait(
  (finalResult) => {
    console.log(`Finished search. Total found: ${finalResult.total}`);
  },
  (error) => {
    console.error('Search failed:', error.reason);
  }
);
```

### Aborting a Task (`.abort()`)

You can abort any `Task` that is still in the `Pending` state. This is useful for cancelling operations when a user navigates away or closes a modal.

```typescript
const renderTask = engine.renderPage(document, document.pages[0]);

// If the user does something to cancel the operation:
setTimeout(() => {
  console.log('Aborting render task...');
  renderTask.abort({ message: 'User cancelled operation' });
}, 500);

try {
  const blob = await renderTask.toPromise();
} catch (error) {
  // This block will execute because the task was aborted
  if (error.name === 'TaskAbortedError') {
    console.log('Render was successfully aborted.'); // Expected output
  }
}
```

## Static Methods

The `Task` class can be imported directly if you need to access its static methods.

```typescript
import { Task } from "@embedpdf/models";
```

  - `Task.all(tasks)`: Rejects if any task fails.
  - `Task.allSettled(tasks)`: Waits for all tasks to complete, regardless of success or failure.
  - `Task.race(tasks)`: Settles as soon as the first task settles.
  - `Task.withProgress(tasks, onProgress)`: A utility to track the completion progress of an array of tasks.
